package Logic.utils;

import DataStructure.arrayAndList.list.Nodelj;
import Logic.dbUtils.DBTools;
import Logic.dbUtils.FileHandler;
import Logic.dbUtils.SQLTestDataEntity;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;

/**
 * @author liujun
 * @version V1.0
 * @date 2022/3/14 12:25 AM
 * @author-Email ljfirst@mail.ustc.edu.cn
 * @description 单元测试工厂
 */
public class UTFactory {

    // 标识位methodExe:是判断是否执行了方法,标识位methodExeErrorCount:是判断错误了几次
    static int methodExeErrorCount = 0;
    static int methodExe = 0;

    public static void test(String className) throws Exception {
        // 应用不同的测试场景，传入的测试名也不同
        if (className.split("\\.").length > 1) {
            className = className.split("\\.")[className.split("\\.").length - 1];
        }
        Class<?> classByReflect = Class.forName(FileHandler.GetClassPath(className));
        Object instance = classByReflect.newInstance();
        methodExeErrorCount = 0;

        // prepare SQL Data
        List<SQLTestDataEntity> list = null;
        list = DBTools.getSqlResult(className);
        if (list == null || list.size() == 0) {
            System.out.println(className + " 未配置测试案例，请检查测试数据库");
            return;
        }

        for (SQLTestDataEntity entity : list) {
            for (Method method : classByReflect.getMethods()) {
                // 方法名必须含有 "Solution" 或者 "Method"
                if (!method.getName().contains("Solution") && !method.getName().contains("solution")
                        && !method.getName().contains("Method") && !method.getName().contains("method")) {
                    continue;
                }

                switch (buildSwitchWord(method)) {
                    case "1:IntArr:IntArr":
                        // 入参只有一个 并且 输入输出的类型为 "String[] - String[]"
                        oneInParams_InIntArr_OutIntArr(entity, method, instance);
                        break;
                    case "1:StrArr:StrArr":
                        // 入参只有一个 并且 输入输出的类型为 "String[] - String[]"
                        oneInParams_InStrArr_OutStrArr(entity, method, instance);
                        break;
                    case "1:Nodelj:Nodelj":
                        // 入参只有一个 并且 输入输出的类型为 "Nodelj - Nodelj"
                        oneInParams_InNodelj_OutNodelj(entity, method, instance);
                        break;
                    case "1:Str:Int":
                        // 入参只有一个 并且 输入输出的类型为 "String - int"
                        oneInParams_InStr_OutInt(entity, method, instance);
                        break;
                    default:
                        // 其他类别的输入输出
                }
            }
        }
        String word = methodExe < 0 ? className + " 未执行" :
                methodExeErrorCount == 0 ? className + " 测试通过，共通过" + list.size() + "个测试案例" :
                        className + " 存在 " + methodExeErrorCount + " 个测试案例没有通过";
        System.out.println(word);
    }

    public static String buildSwitchWord(Method method) {
        Class<?>[] inputParamsTypes = method.getParameterTypes();
        Class<?> outputParamsType = method.getReturnType();
        StringBuilder sb = new StringBuilder();

        // 入参数数量 和 入参类型
        //System.out.println(inputParamsTypes[0].getName());
        //System.out.println(outputParamsType.getName());

        if (inputParamsTypes.length == 1 && inputParamsTypes[0].getName().equals("int")) {
            sb.append("1:Int:");
        }
        if (inputParamsTypes.length == 1 && inputParamsTypes[0].getName().equals("[I")) {
            sb.append("1:IntArr:");
        }
        if (inputParamsTypes.length == 1 && inputParamsTypes[0].getName().equals("java.lang.String")) {
            sb.append("1:Str:");
        }
        if (inputParamsTypes.length == 1 && inputParamsTypes[0].getName().equals("[Ljava.lang.String;")) {
            sb.append("1:StrArr:");
        }
        if (inputParamsTypes.length == 1 && inputParamsTypes[0].getName().contains("Nodelj")) {
            sb.append("1:Nodelj:");
        }

        // 出参类型
        switch (outputParamsType.getName()) {
            case "int":
                sb.append("Int");
                break;
            case "[I":
                sb.append("IntArr");
                break;
            case "java.lang.String":
                sb.append("Str");
                break;
            case "[Ljava.lang.String;":
                sb.append("StrArr");
                break;
            case "Nodelj":
                sb.append("Nodelj");
                break;
            case "void":
                sb.append(getLastString(sb.toString()));
                break;
        }
        return sb.toString();
    }


    // oneParams_InIntArr_OutIntArr : 入参只有一个 并且 输入输出的类型为 "int[] - int[]"
    public static void oneInParams_InIntArr_OutIntArr(SQLTestDataEntity entity, Method method, Object instance) throws Exception {
        int[] input = entity.getIntArrayInput();
        int[] exeOutput = null;
        int[] output = entity.getIntArrayOutput();
        methodExe++;

        // void 说明该方法是原址
        if ("void".equals(method.getReturnType().getName())) {
            exeOutput = Arrays.copyOf(input, input.length);
            method.invoke(instance, (Object) exeOutput);
        } else {
            exeOutput = (int[]) method.invoke(instance, (Object) input);
        }

        if (!ArrayUtilsImpl.IntArrayEquals(output, exeOutput)) {
            methodExeErrorCount++;
            entity.print();
            System.out.println("exeOutput: ");
            ArrayUtilsImpl.intArrayPrint(exeOutput);
        }
    }

    // oneParams_InStrArr_OutStrArr : 入参只有一个 并且 输入输出的类型为 "String[] - String[]"
    public static void oneInParams_InStrArr_OutStrArr(SQLTestDataEntity entity, Method method, Object instance) throws Exception {
        String[] input = entity.getStringArrayInput();
        String[] output = entity.getStringArrayOutput();
        String[] exeOutput = (String[]) method.invoke(instance, (Object) input);
        methodExe++;

        if (!ArrayUtilsImpl.StringArrayEquals(output, exeOutput)) {
            methodExeErrorCount++;
            entity.print();
            System.out.println("exeOutput: " + Arrays.deepToString(exeOutput));
        }
    }

    // 入参只有一个 并且 输入输出的类型为 "Nodelj - Nodelj"
    public static void oneInParams_InNodelj_OutNodelj(SQLTestDataEntity entity, Method method, Object instance) throws Exception {
        int[] input = entity.getIntArrayInput();
        int[] output = entity.getIntArrayOutput();
        Nodelj exeOutput = (Nodelj) method.invoke(instance, Nodelj.Array2Nodelj(input));
        methodExe++;

        if (!ArrayUtilsImpl.IntArrayEquals(output, Nodelj.Nodelj2Array(exeOutput))) {
            methodExeErrorCount++;
            entity.print();
        }
    }


    public static void oneInParams_InStr_OutInt(SQLTestDataEntity entity, Method method, Object instance) throws Exception {
        String input = entity.getStringInput();
        int output = entity.getIntOutput();
        int exeOutput = (int) method.invoke(instance, input);
        methodExe++;

        if (exeOutput != output) {
            entity.print();
            methodExeErrorCount++;
            System.out.println("exeOutput:" + exeOutput);
        }
    }

    public static String getLastString(String str) {
        if (str == null || str.length() == 0) {
            return str;
        }
        String[] strArr = str.split(":");
        return strArr[strArr.length - 1];
    }
}
